package com.yhy.common.token;

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import com.yhy.common.utils.ConstantUtil;
import com.yhy.common.utils.RedisUtil;
import net.minidev.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

/**
 * **********************************************************
 *  内容摘要	：<p>jwt 工具辅助类，用于创建/验证token
 ***********************************************************
 */
public class JwtHelper{

	public static final String AUTHORIZATION = "X-AUTH-TOKEN";
	public static final String CURRENT_USER = "USER_ACCOUNT";
	public static final String SYS_USER = "SYS_USER";
	public static final String SOURCE_TYPE = "SRC";

	public static final int TOKEN_EXPIRES_SECONDS = 60*60*8;

    /**
     * 秘钥
     */
    //private static final byte[] SECRET="345R0d227691751vd04467df11ff67JU".getBytes();
	private static final byte[] SECRET="2323223299dddddksfdksldewewewecdwedwedss".getBytes();
    
    /**
     * 初始化head部分的数据为
     * {
     * 		"alg":"HS256",
     * 		"type":"JWT"
     * }
     */
    private static final JWSHeader header=new JWSHeader(JWSAlgorithm.HS256, JOSEObjectType.JWT, null, null, null, null, null, null, null, null, null, null, null);
    
	/**
	 * 生成token，该方法只在用户登录成功后调用
	 * 
	 * @param payload 可以存储用户id，token生成时间，token过期时间等自定义字段
	 * @return token字符串,若失败则返回null
	 */
	public static String createToken(Map<String, Object> payload) {
		String tokenString=null;
		// 创建一个 JWS object
		JWSObject jwsObject = new JWSObject(header, new Payload(new JSONObject(payload)));
		try {
			// 将jwsObject 进行HMAC签名
			jwsObject.sign(new MACSigner(SECRET));
			tokenString=jwsObject.serialize();
		} catch (JOSEException e) {
			System.err.println("签名失败:" + e.getMessage());
			e.printStackTrace();
		}
		return tokenString;
	}
    
    
    
    /**
     * 校验token是否合法，返回Map集合,集合中主要包含    state状态码   data鉴权成功后从token中提取的数据
     * 该方法在过滤器中调用，每次请求API时都校验
     * @param token
     * @return  Map<String, Object>
     */
	public static Map<String, Object> validToken(String token) {
		Map<String, Object> resultMap = new HashMap<String, Object>();
		try {
			JWSObject jwsObject = JWSObject.parse(token);
			Payload payload = jwsObject.getPayload();
			JWSVerifier verifier = new MACVerifier(SECRET);

			if (jwsObject.verify(verifier)) {
				JSONObject jsonOBj = payload.toJSONObject();
				// token校验成功（此时没有校验是否过期）
				resultMap.put("state", TokenState.VALID.toString());
				
				//缓存中能否找到token
				String operatorCode = String.valueOf(jsonOBj.get(JwtHelper.CURRENT_USER));
				String sourceType = String.valueOf(jsonOBj.get(JwtHelper.SOURCE_TYPE));
				Object memToken = JwtHelper.getToken(ConstantUtil.TOKEN_PREFIX + sourceType + operatorCode);

				if(memToken == null){
					resultMap.put("state", TokenState.EXPIRED.toString());
					// 若payload包含ext字段，则校验是否过期
				}
				/*else if (jsonOBj.containsKey("ext")) {
					long extTime = Long.valueOf(jsonOBj.get("ext").toString());
					long curTime = new Date().getTime();
					
					// 过期了
					if (curTime > extTime) {
						resultMap.clear();
						resultMap.put("state", TokenState.EXPIRED.toString());
					}
				}*/
				String key = ConstantUtil.TOKEN_PREFIX +sourceType+operatorCode;
				if(RedisUtil.getExpireTime(key) < 60 * 10) {
					RedisUtil.setExpireTime(key, JwtHelper.TOKEN_EXPIRES_SECONDS);
					RedisUtil.setExpireTime(ConstantUtil.OPERATOR_PREFIX +sourceType+operatorCode, JwtHelper.TOKEN_EXPIRES_SECONDS);
				}
				resultMap.put("data", jsonOBj);
			} else {
				// 校验失败
				resultMap.put("state", TokenState.INVALID.toString());
			}

		} catch (Exception e) {
			//e.printStackTrace();
			// token格式不合法导致的异常
			resultMap.clear();
			resultMap.put("state", TokenState.INVALID.toString());
		}
		return resultMap;
	}	
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		validToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiIxMzQ4MDA0MTcyOSIsInByb2plY3RJZCI6IjYiLCJzcmMiOiJBUFAiLCJpYXQiOjE1MTEzMzkxMDQzNzEsImV4dCI6MTUxMjYzNTEwNDM3MX0.yCbYol4h0uGI9zBYBoWFDIUlBwIuJkEjciNmjmOFQIA");
	}
	
    /**
     * @param timeout 
     * 
     */
	public static void  putToken(String key , String value, int timeout){
		RedisUtil.set(key,value,timeout);
	}
	
	/**
	 * 
	 *  功能描述 :  
	 *  参数及返回值说明：
	 *  	@return
	 *
	 *  修改记录：
	 *  	日期 ：2017年8月9日 上午10:25:42	修改人：  
	 *  	描述	：
	 *
	 */
	public static Object  getToken(String key){
		return RedisUtil.get(key);
	}
	
}


